package com.anjubao.parking.municipal.common.utils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.anjubao.parking.municipal.common.config.DateTimeConfig;
import com.anjubao.parking.municipal.common.global.EnumJsonDeserializer;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

public class U {
	protected static final Logger logger = LoggerFactory.getLogger(U.class);
	public static ObjectMapper objectMapper = new ObjectMapper();
	private static Sequence WORKER = new Sequence();
	static {
//		objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);//不为空数据
//		objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);//蛇形“a_b_c"
		objectMapper.configure(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, true);// 需要getset成对的数据
		objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);// 允许为空
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 允许不存在字段
		objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);// 允许单引号
		objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);// 允许单引号
		objectMapper.registerModule(new ParameterNamesModule()) // 添加对JDK 8 LocalDateTime支持
				.registerModule(new Jdk8Module());

		// 时间
		JavaTimeModule javaTimeModule = new JavaTimeModule();
		javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateTimeConfig.DEFAULT_DATE_TIME_FORMAT)));
		javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DateTimeConfig.DEFAULT_DATE_FORMAT)));
		javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DateTimeConfig.DEFAULT_TIME_FORMAT)));
		javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DateTimeConfig.DEFAULT_DATE_TIME_FORMAT)));
		javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DateTimeConfig.DEFAULT_DATE_FORMAT)));
		javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DateTimeConfig.DEFAULT_TIME_FORMAT)));
		objectMapper.registerModule(javaTimeModule);

		SimpleModule simpleModule = new SimpleModule();
		simpleModule.addDeserializer(Enum.class, new EnumJsonDeserializer());
		objectMapper.registerModule(simpleModule);

	}

	/**
	 * 获取雪花算法有序主键id
	 * 
	 * @return
	 */
	public static Long id() {
		// 依靠redis生成 时间戳+3位自增,自增定时归0
//		StringRedisTemplate bean = ApplicationContextHelper.getBean(StringRedisTemplate.class);
//		String val = "local i=redis.call('incr','INCR_INT')%1000; local t=redis.call('TIME');return (t[1]*1000+t[2]/1000)*1000+i;";
//		DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
//		redisScript.setResultType(Long.class);
//		redisScript.setScriptText(val);
//		return bean.execute(redisScript, Collections.singletonList("INCR_INT"), "");

		/*
		 * return bean.execute(new RedisCallback<Long>() {
		 * 
		 * @Override public Long doInRedis(RedisConnection connection) throws
		 * DataAccessException { JedisCluster jedis = (JedisCluster)
		 * connection.getNativeConnection();
		 * 
		 * Long evalsha = (Long) jedis.eval(val, "INCR_INT"); return evalsha; } },
		 * true);
		 */

		// 雪花算法有序主键
		return WORKER.nextId();
	}

	/**
	 * json序列化
	 * 
	 * @param value
	 * @return
	 */
	public static String json(Object value) {
		try {
			return objectMapper.writeValueAsString(value);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * json反序列化
	 * 
	 * @param json
	 * @param clz
	 * @return
	 */
	public static <T> T readJson(String json, Class<T> clz) {
		if (json != null) {
			try {
				return objectMapper.readValue(json, clz);
			} catch (Exception e) {
				logger.error("json:" + json, e);
			}
		}
		return null;
	}

	/**
	 * json反序列化
	 * 
	 * @param json
	 * @param reference
	 * @return
	 */
	public static <T> T readJson(String json, TypeReference<T> reference) {
		if (json != null) {
			try {
				return objectMapper.readValue(json, reference);
			} catch (Exception e) {
				logger.error("json:" + json, e);
			}
		}
		return null;
	}

	/**
	 * json反序列化
	 * 
	 * @param json
	 * @param reference
	 * @return
	 */
	public static <T> List<T> readListJson(List<String> ls, Class<T> clz) {
		if (ls != null) {
			try {
				List<T> r = new ArrayList<>();
				for (String json : ls) {
					r.add(objectMapper.readValue(json, clz));
				}
				return r;
			} catch (Exception e) {
				logger.error("json:" + U.json(ls), e);
			}
		}
		return null;
	}

	/**
	 * json反序列化
	 * 
	 * @param json
	 * @param reference
	 * @return
	 */
	public static <T> List<T> readListJson(List<String> ls, TypeReference<T> reference) {
		if (ls != null) {
			try {
				List<T> r = new ArrayList<>();
				for (String json : ls) {
					r.add(objectMapper.readValue(json, reference));
				}
				return r;
			} catch (Exception e) {
				logger.error("json:" + U.json(ls), e);
			}
		}
		return null;
	}

	/**
	 * 保留两位小数
	 * 
	 * @param f
	 * @return
	 */
	public static Double scale2(Double f) {
		return new BigDecimal(f).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 保留两位小数
	 * 
	 * @param f
	 * @return
	 */
	public static Double scale2(Float f) {
		return new BigDecimal(f).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 保留两位小数
	 * 
	 * @param f
	 * @return
	 */
	public static Double scale(Float f) {
		return new BigDecimal(f).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 四舍五入0位小数
	 * 
	 * @param f
	 * @return
	 */
	public static Double scale(Double f) {
		return new BigDecimal(f).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 四舍五入0位小数整形
	 * 
	 * @param f
	 * @return
	 */
	public static Integer scale0Int(Double f) {
		return new BigDecimal(f).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
	}

	/**
	 * 进位
	 * 
	 * @param f
	 * @return
	 */
	public static Double scale2RUp(Double f) {
		if (null == f) {
			return null;
		}
		Double f2 = new BigDecimal(f).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
		Double f3 = null;
		Long l = new Float(f2 * 1000).longValue() % 10;// 求金额的分
		if (l > 0) {// 分>0时，进位，否则保持原来
			f3 = new BigDecimal(f2).setScale(2, BigDecimal.ROUND_UP).doubleValue();
		} else {
			f3 = f2;
		}
		return f3;
	}

	/**
	 * 百倍四舍五入
	 * 
	 * @param f
	 * @return
	 */
	public static Long long100(Double f) {
		if (null == f) {
			return null;
		}
		return new BigDecimal(f * 100).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
	}

	/**
	 * 四舍五入转整形
	 * 
	 * @param f
	 * @return
	 */
	public static Integer toInt(Double f) {
		if (null == f) {
			return null;
		}
		return new BigDecimal(f).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
	}

	/**
	 * 是否为空
	 * 
	 * @param obj
	 * @return {true:为空,false:不为空}
	 */
	public static boolean isEmpty(Object obj) {
		if (obj == null) {
			return true;
		}
		if (obj instanceof String) {
			return obj.equals("");
		} else if (obj instanceof Collection) {
			return ((Collection<?>) obj).isEmpty();
		} else if (obj instanceof Map<?, ?>) {
			return ((Map<?, ?>) obj).isEmpty();
		}
		return false;
	}

	/**
	 * 是否不为空 is not null
	 * 
	 * @param obj
	 * @return {true:不为空,false:为空}
	 */
	public static boolean isNotEmpty(Object obj) {
		return !isEmpty(obj);
	}
}
